// HttpSession.java - A class that implements javax.servlet.http.HttpSession.
//
// Copyright (C) 1999-2002  Smart Software Consulting
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Smart Software Consulting
// 1688 Silverwood Court
// Danville, CA  94526-3079
// USA
//
// http://www.smartsc.com
//

package com.smartsc.http;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Random;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionContext;

public class
HttpSession
implements javax.servlet.http.HttpSession
{
	protected
	HttpSession( int maxInactiveInterval)
	{
		creationTime = System.currentTimeMillis();
		lastAccessedTime = -1;
		this.maxInactiveInterval = maxInactiveInterval;

		// Create session id
		long l = idSeq.nextLong() ^ idSeq.nextLong();
		if( l < 0) l = -l;
		id = String.valueOf( l);

		// Create Hashtable for values
		values = new Hashtable();
	}

	synchronized // package access only
	void
	setLastAccessedTime()
	{
		lastAccessedTime = System.currentTimeMillis();
		newFlag = false;
	}

	protected synchronized
	void
	validate()
	{
		if( !valid)
			throw new IllegalStateException(
				"Session " + id + " has been invalidated.");
	}

	protected
	void
	valueBound( String name, Object value)
	{
		if( value != null && value instanceof HttpSessionBindingListener)
		{
			((HttpSessionBindingListener)value).valueBound(
				new HttpSessionBindingEvent( this, name));
		}
	}

	protected
	void
	valueUnbound( String name, Object value)
	{
		if( value != null && value instanceof HttpSessionBindingListener)
		{
			((HttpSessionBindingListener)value).valueUnbound(
				new HttpSessionBindingEvent( this, name));
		}
	}

	private boolean valid = true;
	private boolean newFlag = true;
	private long creationTime;
	private long lastAccessedTime;
	private int maxInactiveInterval;
	private String id;
	private Hashtable values = null;

	private static Random idSeq = new Random();

	// From javax.servlet.http.HttpSession
	public synchronized long getCreationTime()
	{
		validate();
		return creationTime;
	}
	public synchronized String getId()
	{
		validate();
		return id;
	}
	public synchronized long getLastAccessedTime()
	{
		validate();
		return lastAccessedTime;
	}
	public /* ??? synchronized*/ int getMaxInactiveInterval()
	{
		// ??? validate();
		return maxInactiveInterval;
	}
	public synchronized HttpSessionContext getSessionContext()
	{
		validate();
		return null;
	}
	/** @deprecated */
	public synchronized Object getValue( String name)
	{
		return getAttribute( name);
	}
	public synchronized Object getAttribute( String name)
	{
		validate();
		return values.get( name);
	}
	/** @deprecated */
	public synchronized String[] getValueNames()
	{
		validate();
		String[] s = new String[values.size()];
		Enumeration e = getAttributeNames();
		for( int i = 0; e.hasMoreElements(); ++i)
		{
			s[i] = (String)e.nextElement();
		}
		return s;
	}
	public synchronized Enumeration getAttributeNames()
	{
		return values.keys();
	}
	public synchronized void invalidate()
	{
		validate();
		valid = false;
		HttpRequest.removeSession( id);
		// Un-bind all attribute values
		Enumeration keys = values.keys();
		while( keys.hasMoreElements())
		{
			String key = (String)keys.nextElement();
			valueUnbound( key, values.get( key));
		}
		values.clear();
	}
	public synchronized boolean isNew()
	{
		validate();
		return newFlag;
	}
	/** @deprecated */
	public synchronized void putValue( String name, Object value)
	{
		setAttribute( name, value);
	}
	public synchronized void setAttribute( String name, Object value)
	{
		validate();
		// TODO Detect infinite loop?
		removeAttribute( name);
		values.put( name, value);
		valueBound( name, value);
	}
	/** deprecated */
	public synchronized void removeValue( String name)
	{
		removeAttribute( name);
	}
	public synchronized void removeAttribute( String name)
	{
		validate();
		// TODO Detect infinite loop?
		Object value = getAttribute( name);
		if( value != null)
		{
			values.remove( name);
			valueUnbound( name, value);
		}
	}
	public synchronized void setMaxInactiveInterval( int maxInactiveInterval)
	{
		validate();
		this.maxInactiveInterval = maxInactiveInterval;
	}
}